//=========================================================================
// Copyright (C) 2024 The C++ Component Model(COMO) Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=========================================================================

/**
 * Persistent Memory Library Tests
 */

#include <config.h>
#include <stdio.h>
#include <time.h>
#include "check_common.h"
#include "pmalloc.h"

#define PM_CAPACITY 1024LL * 1024 * 1024 * 10
#define PM_MAX_ALLOCSIZE 1024LL * 20  // 1024 * 200
#define PM_MIN_ALLOCSIZE 1LL
#define MAX_FREE_COUNT PMALLOC_KEYS
#define MAX_ALLOC_COUNT 200
#define SIMULATE_COUNT 10000

TEST(PmallocTest, TestPmsimulate)
{
    // printf("Start checking test simulate %d times in max block size %lld . \n",
    //        SIMULATE_COUNT, PM_MAX_ALLOCSIZE);
    int fd = open("pmsimulate_ds.dat", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    ASSERT_GE(fd, 0) << "open file fail";

    void *md = pmalloc_attach(fd, nullptr, PM_CAPACITY, false);
    ASSERT_NE(md, nullptr) << "pmalloc_attach fail";

    init_random();

    void *data;
    size_t j;
    long simcnt, i, alloccnt, freecnt, cnt, maxalloccnt, maxfreecnt;
    for (simcnt = 0;  simcnt < SIMULATE_COUNT;  simcnt++) {
        cnt = 0;
        maxalloccnt = random_number(1, MAX_ALLOC_COUNT);
        for (alloccnt = 0;  alloccnt < maxalloccnt;  alloccnt++) {
            for (i = 0;  i < PMALLOC_KEYS;  i++)
                if (nullptr == pmalloc_getkey(md, i)) {
                    break;
                }
            if (i < PMALLOC_KEYS) {
                j = random_number(PM_MIN_ALLOCSIZE, PM_MAX_ALLOCSIZE);
                data = pmalloc(md, j);
                if (nullptr == data) {
                    break;
                }
                pmalloc_setkey(md, i, data);
                cnt++;
                // printf(ANSI_COLOR_BLUE
                //        "(Size %zx) Allocated data at %p with key %ld "
                //        "\n" ANSI_COLOR_RESET,
                //        j, data, i);
            }
            else {
                break;
            }
        }
        // printf(ANSI_COLOR_MAGENTA
        //        "Allocated %ld memory blocks \n" ANSI_COLOR_RESET,
        //        cnt);

        cnt = 0;
        maxfreecnt = random_number(1, MAX_FREE_COUNT);
        for (freecnt = 0;  freecnt < maxfreecnt;  freecnt++) {
            i = random_number(0, PMALLOC_KEYS);
            if (free_keydata(md, i) == 0) {
                cnt++;
            }
        }
        // printf(ANSI_COLOR_MAGENTA "Freed %ld memory blocks \n" ANSI_COLOR_RESET,
        //        cnt);
    }

    pmalloc_detach(md);
    close(fd);
    //printf("PM Closed.\n");
}

/*原项目在CTest下的测试用例代码*/

// int main() {
//     printf("Start checking test simulate %d times in max block size %lld . \n",
//            SIMULATE_COUNT, PM_MAX_ALLOCSIZE);
//     int fd = open("pmsimulate_ds.dat", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
//     if (fd < 0) {
//         printf(ANSI_COLOR_RED "Open test data file failure." ANSI_COLOR_RESET);
//         return 1;
//     }

//     void *md = pmalloc_attach(fd, nullptr, PM_CAPACITY);
//     assert(nullptr != md);

//     init_random();

//     void *data;
//     size_t j;
//     long simcnt, i, alloccnt, freecnt, cnt, maxalloccnt, maxfreecnt;
//     for (simcnt = 0; simcnt < SIMULATE_COUNT; ++simcnt) {
//         cnt = 0;
//         maxalloccnt = random_number(1, MAX_ALLOC_COUNT);
//         for (alloccnt = 0; alloccnt < maxalloccnt; ++alloccnt) {
//             for (i = 0; i < PMALLOC_KEYS; ++i)
//                 if (nullptr == pmalloc_getkey(md, i))
//                     break;
//             if (i < PMALLOC_KEYS) {
//                 j = random_number(PM_MIN_ALLOCSIZE, PM_MAX_ALLOCSIZE);
//                 data = pmalloc(md, j);
//                 if (nullptr == data)
//                     break;
//                 pmalloc_setkey(md, i, data);
//                 ++cnt;
//                 printf(ANSI_COLOR_BLUE
//                        "(Size %zx) Allocated data at %p with key %ld "
//                        "\n" ANSI_COLOR_RESET,
//                        j, data, i);
//             } else
//                 break;
//         }
//         printf(ANSI_COLOR_MAGENTA
//                "Allocated %ld memory blocks \n" ANSI_COLOR_RESET,
//                cnt);

//         cnt = 0;
//         maxfreecnt = random_number(1, MAX_FREE_COUNT);
//         for (freecnt = 0; freecnt < maxfreecnt; ++freecnt) {
//             i = random_number(0, PMALLOC_KEYS);
//             if (free_keydata(md, i) == 0)
//                 ++cnt;
//         }
//         printf(ANSI_COLOR_MAGENTA "Freed %ld memory blocks \n" ANSI_COLOR_RESET,
//                cnt);
//     }

//     pmalloc_detach(md);
//     close(fd);
//     printf("PM Closed.\n");
//     return 0;
// }
